前兩篇已經建立了一個簡單的 Web API,並整合 Deployment、Service、ConfigMap、Secret、PVC 和 Ingress。
目前應用程式已經能夠接收 HTTP 請求,也能夠將資料保存到持久化儲存空間。
不過,當應用程式發生問題時,Kubernetes 要如何判斷容器是否正常?又該如何限制容器使用的資源?
這篇將延續前面的專案,加入 Probe 和資源限制,最後透過故障模擬觀察 Kubernetes 的處理方式。
首先修改 DAY28 的 app.py,在原本程式中新增兩個 API:
@app.route("/health")
def health():
return jsonify({
"status": "healthy"
})
@app.route("/ready")
def ready():
try:
if not os.path.isdir(DATA_DIR):
raise RuntimeError("Data directory not found")
if not os.access(DATA_DIR, os.R_OK | os.W_OK):
raise RuntimeError("Data directory not accessible")
load_messages()
return jsonify({
"status": "ready"
})
except (OSError, ValueError, RuntimeError):
return jsonify({
"status": "not ready"
}), 503
這兩個 API 的用途不同:
/health:確認應用程式的 HTTP 服務仍然能夠回應。/ready:檢查應用程式是否具備基本的資料目錄存取能力,以及資料檔案是否能正常讀取。這裡的健康檢查只是一個簡化範例,並不能涵蓋所有應用程式故障。
其中 /ready 也沒有實際測試寫入,因此不能保證儲存空間一定可以成功寫入資料。
由於修改了應用程式,需要重新建立映像檔:
docker build -t k8s-final-demo:3.0 .
接著載入 Minikube:
minikube image load k8s-final-demo:3.0
這次使用新的 Tag,避免和前面建立的映像檔混淆。
接下來修改 k8s/deployment.yaml,加入 Probe 與資源限制。
完整設定如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: final-demo
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: final-demo
template:
metadata:
labels:
app: final-demo
spec:
containers:
- name: web
image: k8s-final-demo:3.0
imagePullPolicy: Never
ports:
- containerPort: 5000
envFrom:
- configMapRef:
name: final-demo-config
- secretRef:
name: final-demo-secret
volumeMounts:
- name: app-data
mountPath: /data
resources:
requests:
cpu: "100m"
memory: "64Mi"
limits:
cpu: "500m"
memory: "256Mi"
startupProbe:
httpGet:
path: /health
port: 5000
periodSeconds: 5
failureThreshold: 12
livenessProbe:
httpGet:
path: /health
port: 5000
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 5000
periodSeconds: 5
failureThreshold: 3
volumes:
- name: app-data
persistentVolumeClaim:
claimName: final-demo-pvc
這份 YAML 延續 DAY28 的 PVC 設定,並新增三種 Probe 和 CPU、Memory 限制。
DAY15 已介紹過 Kubernetes 的健康檢查機制,這裡直接將它整合到實際應用程式。
Startup Probe 用來判斷應用程式是否已完成啟動。
startupProbe:
httpGet:
path: /health
port: 5000
periodSeconds: 5
failureThreshold: 12
在 Startup Probe 成功前,Kubernetes 不會執行 Liveness Probe 和 Readiness Probe。
這個範例大約提供最多 60 秒的啟動檢查時間。
Liveness Probe 用來判斷容器是否需要重新啟動。
livenessProbe:
httpGet:
path: /health
port: 5000
periodSeconds: 10
failureThreshold: 3
如果健康檢查連續失敗達到設定門檻,kubelet 會重新啟動容器。
Readiness Probe 用來判斷 Pod 是否準備好接收流量。
readinessProbe:
httpGet:
path: /ready
port: 5000
periodSeconds: 5
failureThreshold: 3
如果 Readiness Probe 失敗,Pod 會被標記為 NotReady,Service 不會再將一般流量轉送到這個未就緒的 Pod。
但 Readiness Probe 失敗本身不會導致容器重新啟動。
除了 Probe,這次也加入資源限制:
resources:
requests:
cpu: "100m"
memory: "64Mi"
limits:
cpu: "500m"
memory: "256Mi"
其中:
requests.cpu:排程時要求至少配置 100m CPU。requests.memory:排程時要求 64Mi Memory。limits.cpu:限制容器可使用的 CPU 資源。limits.memory:設定容器的 Memory 使用上限。當容器持續使用超過 CPU Limit 的運算資源時,可能受到 CPU Throttling 限制。
如果容器記憶體使用量超過限制,則可能發生 OOM Kill。
這裡的資源數值只是示範,實際環境應根據應用程式的使用情況調整。
完成 YAML 後,執行:
kubectl apply -f k8s/deployment.yaml
等待 Pod 重新建立:
kubectl rollout status deployment/final-demo
查看 Pod:
kubectl get pods
正常情況下,Pod 應該進入 Running,並且顯示 Ready。
也可以查看詳細資訊:
kubectl describe pod <pod-name>
在 Containers 區塊中,可以找到 Liveness、Readiness、Startup Probe,以及 Requests、Limits 的設定。
接下來故意修改 Readiness Probe,讓 Kubernetes 無法通過健康檢查。
將 Deployment 中的:
readinessProbe:
httpGet:
path: /ready
port: 5000
暫時修改成:
readinessProbe:
httpGet:
path: /wrong-path
port: 5000
由於應用程式沒有 /wrong-path 這個 API,因此 HTTP 請求會回傳 404。
重新套用 Deployment:
kubectl apply -f k8s/deployment.yaml
接著查看 Pod:
kubectl get pods -w
由於 Readiness Probe 無法通過,Pod 會顯示:

這裡可以觀察到:
Pod 處於 Running,並不代表它已經準備好接收流量。
接著查看 Pod 事件:
kubectl describe pod <pod-name>
可能會看到類似:

這表示 Kubernetes 已經偵測到 Readiness Probe 失敗。
不過,因為 Liveness Probe 仍然正常,容器不會只因為 Readiness Probe 失敗就重新啟動。
接著查看 Service 對應的 EndpointSlice:
kubectl get endpointslices -l kubernetes.io/service-name=final-demo-service
也可以查看詳細內容:
kubectl describe endpointslice <endpointslice-name>
當 Pod 的 Readiness Probe 失敗時,對應端點的 Ready 狀態會變成 false。
Service 一般不會將新的連線轉送到未就緒的端點。
由於目前只有一個 Pod,因此當它無法通過 Readiness Probe 時,Service 可能沒有可用的後端。
這也說明 Readiness Probe 的重要性:避免應用程式尚未準備好時就接收請求。
完成觀察後,將路徑改回:
readinessProbe:
httpGet:
path: /ready
port: 5000
重新套用:
kubectl apply -f k8s/deployment.yaml
等待 Deployment 更新完成:
kubectl rollout status deployment/final-demo
再次查看 Pod:
kubectl get pods
正常情況下,Pod 應該恢復 Ready 狀態。
接下來測試 Liveness Probe。
將 Deployment 中的 Liveness Probe 修改成:
livenessProbe:
httpGet:
path: /wrong-health
port: 5000
periodSeconds: 10
failureThreshold: 3
由於 /wrong-health 不存在,Liveness Probe 會持續收到 HTTP 404。
重新部署:
kubectl apply -f k8s/deployment.yaml
接著觀察:
kubectl get pods -w
當 Liveness Probe 連續失敗達到設定門檻後,kubelet 會重新啟動容器。
這時可以觀察 Pod 的 RESTARTS 欄位。
也可以透過:
kubectl describe pod <pod-name>
查看相關事件。
可能會看到:

與 Readiness Probe 不同,Liveness Probe 失敗會觸發容器重新啟動。
如果問題持續存在,容器就可能不斷重新啟動。
當容器重新啟動後,可以使用:
kubectl logs <pod-name> --previous
查看上一個已終止容器實例的日誌。
如果容器仍在正常執行,也可以使用:
kubectl logs <pod-name>
查看目前的日誌。
這些指令在 DAY24 已經介紹過,這裡可以實際搭配 Probe 故障使用。
如果容器尚未重新啟動,或上一個容器實例的日誌已經無法取得,
--previous可能會出現錯誤。
完成測試後,將 Liveness Probe 改回:
livenessProbe:
httpGet:
path: /health
port: 5000
periodSeconds: 10
failureThreshold: 3
重新部署:
kubectl apply -f k8s/deployment.yaml
等待 Deployment 恢復:
kubectl rollout status deployment/final-demo
查看狀態:
kubectl get pods
最後可以再次測試 API,確認應用程式已經恢復正常。
這篇延續前兩篇建立的 Kubernetes 應用程式,整合了 Probe、資源限制與故障排查。
透過實際修改健康檢查路徑,可以觀察到:
到這裡,已經完成一個簡單的 Kubernetes 應用程式部署,並且整合了設定管理、資料持久化、網路存取、健康檢查與基本維運。
雖然這個範例距離正式的生產環境還有不少差距,例如高可用性、備份、監控與安全管理,但已經涵蓋了 Kubernetes 的多項核心功能。
下一篇 DAY30 將回顧整個系列學過的內容,並整理後續可以繼續學習的方向,為這次的 30 天 Kubernetes 入門系列畫下句點。